import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

@Slf4j
public class SelectorTest {

    public static void main(String[] args) throws IOException {

        Selector selector = Selector.open();

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 非阻塞
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.bind(new InetSocketAddress(80));

        ByteBuffer charBuffer = ByteBuffer.allocate(1024);

        // 注册事件,并且附带一个对象。
        SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT, charBuffer);
        log.info("当前注册key={}", key);

        // 感兴趣的事件
        int ops = key.interestOps();

        // 判断一个事件是否在当前感兴趣的集合当中。
        boolean isInterestedInAccept = (ops & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT;
        log.info("判断一个事件是否在当前感兴趣的集合当中={}", isInterestedInAccept);

        // 检查当前事件是否已准备
        boolean isAcceptable = key.isAcceptable();
        log.info("当前接收是否准备好了={}", isAcceptable);

        // 当前key 附带的 Channel and Selector and Object
        Channel channel = key.channel();
        Selector selector1 = key.selector();
        Object attachment = key.attachment();

        while (true) {

            // select 阻塞,当前准备好的通道
            int readyChannels = selector.select();
            if (readyChannels == 0) continue;

            // !=0 则表示一个或者多个准备好了
            Set<SelectionKey> keySet = selector.selectedKeys();
            Iterator<SelectionKey> iterator = keySet.iterator();

            while (iterator.hasNext()) {

                SelectionKey item = iterator.next();

                // 是否准备好接收
                if (item.isAcceptable()) {
                    log.info("item isAcceptable is true");


                    Channel itemSelect = item.channel();
                    ServerSocketChannel itemServerChannel = (ServerSocketChannel) itemSelect;

                    // 获得数据管道
                    SocketChannel socketChannel = itemServerChannel.accept();
                    ByteBuffer buffer = (ByteBuffer)item.attachment();

                    // 写入数据
                    buffer.put("HTTP/1.1 200 ok\n".getBytes());
                    buffer.put("Content-Type: text/html; charset=UTF-8\n".getBytes());
                    buffer.put("Content-Length: 4\n".getBytes());
                    buffer.put("\n".getBytes());
                    buffer.put("abcd".getBytes());

                    buffer.flip();

                    socketChannel.write(buffer);
                    buffer.clear();
                    socketChannel.close();
                    // 是否准备好连接
                } else if (item.isConnectable()) {
                    log.info("item isConnectable is true");
                    // 是否准备好读取
                } else if (item.isReadable()) {
                    log.info("item isReadable is true");
                    // 是否准备好写入
                } else if (item.isWritable()) {
                    log.info("item isWritable is true");
                }

                // 移除当前remove
                iterator.remove();
            }

        }

    }

}
